﻿using System;
using System.Buffers;
using System.Threading;
using System.Threading.Tasks;
using TiffLibrary;
using WholeSlideImageLibrary.Formats.GenericTiff;

namespace WholeSlideImageLibrary.Formats.PhilipsTiff
{
    public class PhilipsTiffImageIdentifier : IImageIdentifier
    {
        public string Name => "PhilipsTiff";

        public int HeaderSize => 16;

        public async ValueTask<ImageSourceType> IdentifyAsync(FileSourceInfo fileInfo, FileSourceReader reader, ReadOnlyMemory<byte> header, CancellationToken cancellationToken = default)
        {
            if (reader is null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (header.Length < HeaderSize)
            {
                return ImageSourceType.None;
            }
            if (!TiffFileHeader.TryParse(header.Span, out _))
            {
                return ImageSourceType.None;
            }

            TiffFileReader? tiff = await TiffFileReader.OpenAsync(new FileSourceReaderSimpleContentSource(reader), true, cancellationToken).ConfigureAwait(false);
            await using (tiff.ConfigureAwait(false))
            {
                TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(cancellationToken).ConfigureAwait(false);
                TiffImageFileDirectoryEntry descriptionTag = ifd.FindEntry(TiffTag.ImageDescription);
                if (descriptionTag.Tag != TiffTag.ImageDescription)
                {
                    // 没有 ImageDescription Tag
                    return ImageSourceType.None;
                }
                // ImageDescription 应该是XML文档
                // <?xml version="1.0" encoding="UTF-8" ?>
                // "<DataObject "
                // 不含换行符，一共是51个字节
                if (descriptionTag.ValueCount < 51)
                {
                    return ImageSourceType.None;
                }

                // 51个字节一定不会是TIFF inline tag
                // 因此可以直接从文件流中读取，而不需要使用TiffFieldReader
                // 这里直接读取256个字节，容忍一定程度的换行和空格
                int readCount = (int)Math.Min(descriptionTag.ValueCount, 256);
                byte[] buffer = ArrayPool<byte>.Shared.Rent(readCount);
                try
                {
                    int readResult = await reader.ReadAsync(descriptionTag.ValueOffset, buffer.AsMemory(0, readCount), cancellationToken).ConfigureAwait(false);

                    if (!ValidateDescriptionHeader(buffer.AsSpan(0, readResult)))
                    {
                        return ImageSourceType.None;
                    }
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(buffer);
                }

                PhilipsTiffXmlMetadata? metadata;

                // 读取全部XML并尝试解析字段
                readCount = (int)descriptionTag.ValueCount;
                buffer = ArrayPool<byte>.Shared.Rent(readCount);
                try
                {
                    int readResult = await reader.ReadAsync(descriptionTag.ValueOffset, buffer.AsMemory(0, readCount), cancellationToken).ConfigureAwait(false);

                    metadata = PhilipsTiffXmlMetadataParser.Parse(buffer, 0, readResult);
                    if (metadata is null)
                    {
                        return ImageSourceType.None;
                    }
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(buffer);
                }

                // 验证XML内容
                if (!PhilipsTiffXmlMetadataValidator.Validate(metadata))
                {
                    return ImageSourceType.None;
                }

                if (metadata.ScanedImages!.Length == 0)
                {
                    return ImageSourceType.None;
                }

                return ImageSourceType.SingleImage;
            }
        }

        private static bool ValidateDescriptionHeader(ReadOnlySpan<byte> buffer)
        {
            // 检查XML头部
            ReadOnlySpan<byte> xmlPrefix = new byte[] { (byte)'<', (byte)'?', (byte)'x', (byte)'m', (byte)'l', (byte)' ', (byte)'v', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n', (byte)'=', (byte)'"', (byte)'1', (byte)'.', (byte)'0', (byte)'"', (byte)' ', (byte)'e', (byte)'n', (byte)'c', (byte)'o', (byte)'d', (byte)'i', (byte)'n', (byte)'g', (byte)'=', (byte)'"', (byte)'U', (byte)'T', (byte)'F', (byte)'-', (byte)'8', (byte)'"', (byte)' ', (byte)'?', (byte)'>' };
            if (!buffer.StartsWith(xmlPrefix))
            {
                return false;
            }
            buffer = buffer.Slice(xmlPrefix.Length);

            // 删除\r \n 和 空格
            int firstValidChar = buffer.Length;
            for (int i = 0; i < buffer.Length; i++)
            {
                byte b = buffer[i];
                if (b != (byte)'\r' && b != (byte)'\n' && b != (byte)' ')
                {
                    firstValidChar = i;
                    break;
                }
            }
            buffer = buffer.Slice(firstValidChar);

            // 检查DataObject头部
            ReadOnlySpan<byte> dataObjectPrefix = new byte[] { (byte)'<', (byte)'D', (byte)'a', (byte)'t', (byte)'a', (byte)'O', (byte)'b', (byte)'j', (byte)'e', (byte)'c', (byte)'t', (byte)' ' };
            return buffer.StartsWith(dataObjectPrefix);
        }

        public ValueTask<ImageSourceType> IdentifyAsync(DirectorySourceInfo directoryInfo, CancellationToken cancellationToken = default)
        {
            return new ValueTask<ImageSourceType>(ImageSourceType.None);
        }

        public ValueTask<WholeSlideImageCollection?> OpenImageCollectionAsync(FileSourceInfo fileInfo, FileSourceReader reader, CancellationToken cancellationToken = default)
        {
            return default;
        }

        public ValueTask<WholeSlideImageCollection?> OpenImageCollectionAsync(DirectorySourceInfo directoryInfo, CancellationToken cancellationToken = default)
        {
            return default;
        }

        public async ValueTask<WholeSlideImage?> OpenSingleImageAsync(FileSourceInfo fileInfo, FileSourceReader reader, CancellationToken cancellationToken = default)
        {
            if (reader is null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            TiffFileReader? tiff = await TiffFileReader.OpenAsync(new FileSourceReaderSimpleContentSource(reader), true, cancellationToken).ConfigureAwait(false);
            await using (tiff.ConfigureAwait(false))
            {
                TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(cancellationToken).ConfigureAwait(false);
                TiffImageFileDirectoryEntry descriptionTag = ifd.FindEntry(TiffTag.ImageDescription);
                if (descriptionTag.Tag != TiffTag.ImageDescription)
                {
                    // 没有 ImageDescription Tag
                    return null;
                }
                // ImageDescription 应该是XML文档
                // <?xml version="1.0" encoding="UTF-8" ?>
                // "<DataObject "
                // 不含换行符，一共是51个字节
                if (descriptionTag.ValueCount < 51)
                {
                    return null;
                }

                // 51个字节一定不会是TIFF inline tag
                // 因此可以直接从文件流中读取，而不需要使用TiffFieldReader
                // 这里直接读取256个字节，容忍一定程度的换行和空格
                int readCount = (int)Math.Min(descriptionTag.ValueCount, 256);
                byte[] buffer = ArrayPool<byte>.Shared.Rent(readCount);
                try
                {
                    int readResult = await reader.ReadAsync(descriptionTag.ValueOffset, buffer.AsMemory(0, readCount), cancellationToken).ConfigureAwait(false);

                    if (!ValidateDescriptionHeader(buffer.AsSpan(0, readResult)))
                    {
                        return null;
                    }
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(buffer);
                }

                PhilipsTiffXmlMetadata? metadata;

                // 读取全部XML并尝试解析字段
                readCount = (int)descriptionTag.ValueCount;
                buffer = ArrayPool<byte>.Shared.Rent(readCount);
                try
                {
                    int readResult = await reader.ReadAsync(descriptionTag.ValueOffset, buffer.AsMemory(0, readCount), cancellationToken).ConfigureAwait(false);

                    metadata = PhilipsTiffXmlMetadataParser.Parse(buffer, 0, readResult);
                    if (metadata is null)
                    {
                        return null;
                    }
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(buffer);
                }

                // 验证XML内容
                if (!PhilipsTiffXmlMetadataValidator.Validate(metadata))
                {
                    return null;
                }

                if (metadata.ScanedImages!.Length == 0)
                {
                    return null;
                }

                var wsi = new PhilipsTiffWholeSlideImage(fileInfo, metadata.ScanedImages[0]);
                await wsi.InitializeAsync(cancellationToken).ConfigureAwait(false);
                return wsi;
            }
        }

        public ValueTask<WholeSlideImage?> OpenSingleImageAsync(DirectorySourceInfo directoryInfo, CancellationToken cancellationToken = default)
        {
            return default;
        }
    }
}
